#!/bin/sh
# Bug reports and comments to Igor.Ermolaev@intel.com
source $(dirname $(readlink -f ${BASH_SOURCE[0]:-$0}))/find_loop

knwn_fncs=( __libc_start_main __kmp_invoke_microtask `echo "$TRACING_SDK_FIND_CALL_INDR"|tr , ' '` )

saveIFS=$IFS;IFS='
'; if [ $# -eq 0 ]; then
      addrs_list=( `$base/find_hotspots` )
   else
      addrs_list=( `echo "$@"|sed 's/ -- /\n/g'|$base/find_hotspots -f` )
   fi
IFS=$saveIFS

echo
disasm=`mktemp`
for l in "${addrs_list[@]}"; do
   desc=( $l );weight=${desc[0]};module=${desc[1]};func=${desc[2]};selc=${desc[3]}
 
   module=`$base/addrs2 base "$module"`
   if [ "$func" == -r ] || [ "$func" == -c ]; then
      line=`$base/addrs2 abs "$module" "$selc"`
      selc="$func $line"
      func=-r
      unset ctgt
   else
      re='^[^:]+:[0-9]+?$';if [[ "$selc" =~ $re ]]; then
         line="$selc"
         unset ctgt
      else
         ctgt="$selc"
         selc=-a
         unset line
      fi
   fi
   
   echo Processing $addr from $(basename ${module%%:[0-9]*}) with weight: $weight
   call=call.$isa.s
   $base/get_disasm ${module%%:[0-9]*} $func${line:+ $line}|$base/get_call $selc 5 5 -l -s -f${ctgt:+ -t $ctgt}${TRACING_SDK_FIND_CALL_IDX:+ -i $TRACING_SDK_FIND_CALL_IDX} >$call
   var=$(grep -c ';===' $call)
   if [ $var -ne 1 ]; then
      continue
   fi
   caddr=`$base/get_ranges <$call|head -n 1|awk '{print $2}'`
   if [ -z "$caddr" ] || [ "$caddr" == -1 ]; then
      continue
   fi
   if [ -z "$ctgt" ]; then
      func=`grep -P ';---\s+.+' $call|sed 's/;---\s\+\([^: ]\+\).*/\1/'`
      line=`$base/find_lines <$call|head -n 1`
      if [ -n "$line" ]; then selc="$line"; else selc=-a; fi
      cid=`echo $caddr|sed 's/^\(0x\)\?0*\(.\)/\2/'`
      ctgt=`sed -n 's/^\s*\(0x\)\?0*'$cid'\s*:\s*call\S\+\s\+\S\+\s*<\([^+]\+\)>.*$/\2/p' $call`
      if [ -z "$ctgt" ]; then # indirect call
         if [ "$TRACING_SDK_FIND_CALL_INDR" != +all ] && [ -z "$line" ]; then
            is_knwn=false
            for f in "${knwn_fncs[@]}"; do
               if [[ "$func" == $f ]]; then is_knwn=true;break; fi
            done
            if [ $is_knwn == false ]; then continue; fi
         fi
      fi
      if [ -n "$ctgt" ]; then ctgt=" -t $ctgt"; fi
      $base/get_disasm ${module%%:[0-9]*} $func${line:+ $line}|$base/get_call $selc 5 5 -l -s -f$ctgt >$call
   fi
   
   var=$(grep -c ';===' $call)
   if [ $var -gt 1 ]; then
      $base/get_disasm ${module%%:[0-9]*} $func${line:+ $line} >$disasm
      for (( cidx=0; ; cidx++ )); do
         $base/get_call $selc 5 5 -l -s -f$ctgt -i $cidx <$disasm >$call
         var=$(grep -c ';===' $call)
         if [ $var -eq 0 ]; then
            continue 2
         fi
         if [ $var -ne 1 ]; then continue; fi
         if [ `$base/get_ranges <$call|awk '{print $2}'` == $caddr ]; then break; fi
      done
   fi
   saveIFS=$IFS;IFS='
';    ranges=( `$base/get_ranges <$call` )
   IFS=$saveIFS
   for r in "${ranges[@]}"; do
      range=( $r )
      if [ ${range[1]} != $caddr ]; then continue; fi
      echo
      echo 'First, try do whole call tracing using the following command.'
      echo
      echo '   'sde ${tgt:+$tgt }-pinlit -trace-mt -start-address ${range[1]} -stop-address ${range[3]}:1 -length 100000000 ${extra:+$extra }-moi $(basename $module) -- '$@'
      echo
      echo 'If number of instructions in trace is  less than 30M, choose'
      echo 'appropriate  skip  count  for  -stop-address  to get  30-70M'
      echo 'instructions in trace.'
      echo
      if [ "${range[1]}" != "-1" ]; then
         echo "If you'd  like  to  skip  several  call  instances  use  the"
         echo 'following command:'
         echo
         echo '   'sde ${tgt:+$tgt }-pinlit -trace-mt -start-address ${range[1]}:1 -stop-address ${range[3]}:1 -length 100000000 ${extra:+$extra }-moi $(basename $module) -- '$@'
         echo
      fi
      break 2
   done
   echo
   echo '   'Warning: The call\'s site isn\'t found in the module, skipping...
   echo
done

rm $disasm

if [ -z "$range" ]; then
   echo >&2
   echo Can\'t find appropriate call\'s site from profile. >&2
   echo Exact call graph needs to be built for function boundaries extraction. >&2
   echo >&2
fi
